package com.zhaorujie.rpc.bootstrap;

import com.zhaorujie.rpc.core.RpcProperties;
import com.zhaorujie.rpc.core.exception.RpcException;
import com.zhaorujie.rpc.core.remoting.invoker.RpcInvokerFactory;
import com.zhaorujie.rpc.core.remoting.invoker.annotain.RpcReference;
import com.zhaorujie.rpc.core.remoting.invoker.proxy.ServiceProxy;
import com.zhaorujie.rpc.core.remoting.provider.RpcProviderFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;

import java.lang.reflect.Field;
import java.lang.reflect.Proxy;

/**
 * @author 赵汝杰
 * @version v1.0
 * @description RpcSpringInvokerFactoryImpl
 * @date 2024/3/8
 **/
public class RpcSpringInvokerFactory implements InitializingBean, DisposableBean, BeanPostProcessor {

    private final static Logger logger = LoggerFactory.getLogger(RpcSpringInvokerFactory.class);

    private final RpcProperties rpcProperties;

    private RpcInvokerFactory rpcInvokerFactory;

    public RpcSpringInvokerFactory(RpcProperties rpcProperties) {
        this.rpcProperties = rpcProperties;
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        logger.debug("RpcSpringInvokerFactory afterPropertiesSet");
        this.rpcInvokerFactory = new RpcInvokerFactory();
        rpcInvokerFactory.init(rpcProperties);
    }

    /**
     * bean初始化后执行注入服务
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        Class<?> beanClass = bean.getClass();
        // 获取对象的所有属性
        Field[] declaredFields = beanClass.getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.isAnnotationPresent(RpcReference.class)) {
                Class<?> interfaceClass = field.getType();
                if (!interfaceClass.isInterface()) {
                    throw new RpcException("rpc reference(XxlRpcReference) must be interface.");
                }

                RpcReference rpcReference = field.getAnnotation(RpcReference.class);

                // 通过JDK动态代理的方式调用接口
                Object serviceProxy = Proxy.newProxyInstance(interfaceClass.getClassLoader(),
                        new Class[]{interfaceClass},
                        new ServiceProxy(rpcInvokerFactory, rpcReference.version(), rpcReference.timeout(), rpcReference.loadBalance()));
                field.setAccessible(true);
                try {
                    field.set(bean, serviceProxy);
                    field.setAccessible(false);
                } catch (IllegalAccessException e) {
                    throw new RpcException("为字段注入代理对象失败", e);
                }

                String serviceKey = RpcProviderFactory.buildServiceKey(interfaceClass.getName(), rpcReference.version());
                logger.info("rpc invoker factory init reference bean success. serviceKey = {}, bean.field = {}.{}",
                        serviceKey, beanName, field.getName());
            }
        }

        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }

    @Override
    public void destroy() throws Exception {
        logger.debug("RpcSpringInvokerFactory destroy");
        rpcInvokerFactory.destroy();
    }

}
